跳到主要内容

HTTPS 请求中的 SSL 加密过程

SSL 与 HTTPS 关系

我们知道 HTTP 是应用层协议,它会在 IP 寻址,经过三次 TCP 握手,建立 TCP 连接通道后,开始传输数据。在这里,如果有人进行 TCP 抓包,则可以获取到传输的数据,甚至对数据进行篡改,这会造成安全问题。为了解决这个问题,HTTPS 应运而生。

HTTPS 被称为 HTTP Over SSL (基于SSL加密的HTTP),这里的SSL (Secure Socket Layer) 被称为 安全套接层,它是一种加密协议,能加密的东西很多,不止HTTP协议、还有POP3协议、SMTP协议(SMTP Over SSL)、VPN等。当然,还有 TLS (Transport Layer Security) 传输层安全,是公有加密协议,TLS只是对SSLv3做了些修改和增加,有时也一起统称为 SSL。

SSL 位于 协议的哪一层?

数据的源头来源于 HTTP 应用层,而 TCP/IP 负责寻址和数据的打包封装和传输,那对数据的加密,自然就在 HTTP 和 TCP/IP 之间工作了,如下图

原来的数据包

加入SSL之后的数据包

SSL 作用

不使用 SSL/TLS 的 HTTP 通信,就是不加密的通信。所有信息明文传播,带来了三大风险。

(1) 窃听风险(eavesdropping):第三方可以获知通信内容。

(2) 篡改风险(tampering):第三方可以修改通信内容。

(3) 冒充风险(pretending):第三方可以冒充他人身份参与通信。

SSL/TLS协议是为了解决这三大风险而设计的,希望达到:

(1) 所有信息都是加密传播,第三方无法窃听。

(2) 具有校验机制,一旦被篡改,通信双方会立刻发现。

(3) 配备身份证书,防止身份被冒充。

互联网是开放环境,通信双方都是未知身份,这为协议的设计带来了很大的难度。而且,协议还必须能够经受所有匪夷所思的攻击,这使得 SSL/TLS 协议变得异常复杂。

SSL 历史

互联网加密通信协议的历史,几乎与互联网一样长。

1994年,NetScape公司设计了SSL协议(Secure Sockets Layer)的1.0版,但是未发布。

1995年,NetScape公司发布SSL 2.0版,很快发现有严重漏洞。

1996年,SSL 3.0版问世,得到大规模应用。

1999年,互联网标准化组织 ISOC 接替NetScape公司,发布了 SSL 的升级版 TLS 1.0版。

2006年和2008年,TLS进行了两次升级,分别为TLS 1.1版和TLS 1.2版。最新的变动是2011年TLS 1.2的修订版。

目前,应用最广泛的是TLS 1.0,接下来是SSL 3.0。但是,主流浏览器都已经实现了TLS 1.2的支持。

TLS 1.0通常被标示为SSL 3.1,TLS 1.1为SSL 3.2,TLS 1.2为SSL 3.3。

SSL 基本的运行过程

SSL/TLS 协议的基本思路是采用公钥加密法,也就是说,客户端先向服务器端索要公钥,然后用公钥加密信息,服务器收到密文后,用自己的私钥解密。

但是,这里有两个问题。

(1)如何保证公钥不被篡改?

解决方法:将公钥放在数字证书中。只要证书是可信的,公钥就是可信的。

(2)公钥加密计算量太大,如何减少耗用的时间?

解决方法:每一次对话(session),客户端和服务器端都生成一个"对话密钥"(session key),用它来加密信息。由于"对话密钥"是对称加密,所以运算速度非常快,而服务器公钥只用于加密 "对话密钥" 本身,这样就减少了加密运算的消耗时间。

因此,SSL/TLS协议的基本过程是这样的:

(1) 客户端向服务器端索要并验证公钥。

(2) 双方协商生成"对话密钥"。

(3) 双方采用"对话密钥"进行加密通信。

上面过程的前两步,又称为"握手阶段"(handshake)。

注:当建立了 TCP 连接通道后,就可以开始传输 HTTP 头数据了,但是要用 SSL 对 HTTP 数据进行加密。既然是加密,自然涉及到一套加密体系(算法,公钥,私钥等)。但是在浏览器第一次连接服务器进行 HTTPS 请求的时候,客户端是没有这些加密体系的,那要怎么才能获取到?既然客户端没有,那只能从服务端获取了。所以,客户端要先从服务端获取到 SSL 加密体系。

如何获取呢?既然建立了 TCP 连接,那就通过 TCP 连接通道来获取了。

SSL 握手阶段的详细过程

"握手阶段" 涉及四次通信,我们一个个来看。需要注意的是,"握手阶段"的所有通信都是明文的。

1 客户端发出请求(ClientHello)

首先,客户端(通常是浏览器)先向服务器发出加密通信的请求,这被叫做 ClientHello 请求。

在这一步,客户端主要向服务器提供以下信息。

(1) 支持的协议版本,比如TLS 1.0版。

(2) 一个客户端生成的随机数,稍后用于生成"对话密钥"。

(3) 支持的加密方法,比如 RSA 公钥加密。

(4) 支持的压缩方法。

客户端生成一个32位的随机数A (ClientHello.Random),告诉接服务器,我是什么浏览器,我支持哪些 SSL 协议版本号,支持哪些加密算法,压缩方式,Server Name (域名,这样服务器就知道找那个域名的证书发过来,参考 Nginx 的 Server Name)加上 文本内容 “Hello”,发出 ClientHello,开始协商握手。

这里需要注意的是,客户端发送的信息之中不包括服务器的域名。也就是说,理论上服务器只能包含一个网站,否则会分不清应该向客户端提供哪一个网站的数字证书。这就是为什么通常一台服务器只能有一张数字证书的原因。

对于虚拟主机的用户来说(Nginx 绑的子域名),这当然很不方便。2006年,TLS协议加入了一个 Server Name Indication 扩展,允许客户端向服务器提供它所请求的域名。

2 服务器回应(SeverHello)

服务器收到客户端请求后,向客户端发出回应,这叫做 SeverHello。服务器的回应包含以下内容。

(1) 确认使用的加密通信协议版本,比如TLS 1.0版本。如果浏览器与服务器支持的版本不一致,服务器关闭加密通信。

(2) 一个服务器生成的随机数,稍后用于生成"对话密钥"。

(3) 确认使用的加密方法,比如 RSA公钥加密。

(4) 服务器证书。

服务端收到客户端的 ClientHello,知道了客户端的一些信息,比如 SSL协议版本号,加密算法列表,然后和服务端自己支持的版本号和加密算法进行对比,选择出双方都能使用的协议版本号和算法,加上一个 32位的随机数B(ServerHello.Random),把这些信息,打包在一起,向客户端返回一个服务端 Hello (ServerHello),告诉客户端,我选择了哪个协议和算法。

随后服务器给客户端发送一个 Certificate 报文(数字证书),报文中包含服务端的公钥证书(从 CA 数字证书管理机构处获取,在 nginx 配置中相关证书的存放目录)

紧接着服务器给客户端发送 Server Hello Done,表示最初的协商握手过程结束

除了上面这些信息,如果服务器需要确认客户端的身份,就会再包含一项请求,要求客户端提供"客户端证书"。比如,金融机构往往只允许认证客户连入自己的网络,就会向正式客户提供USB密钥,里面就包含了一张客户端证书。

3 客户端回应

客户端收到服务器回应以后,首先验证服务器证书。如果证书不是可信机构颁布、或者证书中的域名与实际域名不一致、或者证书已经过期,就会向访问者显示一个警告,由其选择是否还要继续通信。

如果证书没有问题,客户端就会从证书中取出服务器的公钥。然后,向服务器发送下面三项信息。

(1) 一个随机数。该随机数用服务器公钥加密,防止被窃听。

(2) 编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。

(3) 客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时也是前面发送的所有内容的 hash值,用来供服务器校验。

客户端校验证书等通过后,若采用 RSA,会以 Client Key Exchange 作为回应,再次产生一个48位的随机密码串C 预主密码(Pre-Master Secret),它是整个握手阶段出现的第三个随机数,又称 "pre-master key"。有了它以后,客户端和服务器就同时有了三个随机数:随机数A、随机数B、随机数 Pre-Master Secret,用它们,双方就可以用事先商定的加密方法,各自生成本次会话所用的同一把 "会话密钥"(Master Secret)

客户端发送 Change Cipher Spec 密钥变更说明包,该报文告知服务端,此步骤告诉服务器,之后的所有数据将使用上面生成的 Master Secret 进行加密;

随后客户端发送 Finish 报文,此报文中包含连接至今所有报文的整体校验值,用于完整性验证;

至于为什么一定要用三个随机数,来生成"会话密钥":

"不管是客户端还是服务器,都需要随机数,这样生成的密钥才不会每次都一样。由于SSL协议中证书是静态的,因此十分有必要引入一种随机因素来保证协商出来的密钥的随机性。

对于RSA密钥交换算法来说,pre-master-key本身就是一个随机数,再加上hello消息中的随机,三个随机数通过一个密钥导出器最终导出一个对称密钥。

pre master 的存在在于 SSL 协议不信任每个主机都能产生完全随机的随机数,如果随机数不随机,那么 pre master secret 就有可能被猜出来,那么仅适用 pre master secret 作为密钥就不合适了,因此必须引入新的随机因素,那么客户端和服务器加上 pre master secret 三个随机数一同生成的密钥就不容易被猜出了,一个伪随机可能完全不随机,可是是三个伪随机就十分接近随机了,每增加一个自由度,随机性增加的可不是一。"

此外,如果前一步,服务器要求客户端证书,客户端会在这一步发送证书及相关信息。

4 服务器的最后回应

服务端使用 私钥 对 秘密消息 进行解密,得到 Pre-Master Secret;此时,服务端有了随机数A,随机数B,随机数 Pre-Master Secret,也可以生成 Master Secret了。

服务端发送 Finish 报文给客户端,表示服务端已正确解析客户端发送的整体校验值。

(1)编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。

(2)服务器握手结束通知,表示服务器的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供客户端校验。

至此,整个握手阶段全部结束。接下来,客户端与服务器进入加密通信,就完全是使用普通的HTTP协议,只不过用"会话密钥"加密内容。

补充:这里的生成会话密钥

客户端和服务端,都根据随机数A (ClientHello.random)、随机数B (ServerHello.random)、随机密码串C (Pre-Master Secret)三个参数,通过 PRF (Pseudo-Random Function) 算出 master secret,作为数据传输对称加密的 密钥Session Key。

master_secret = PRF(Pre_master, "master secret", ClientHello.random + ServerHello.random)

上面生成了会话密钥后,开始使用 HTTP 协议,去传输使用 Session Key 加密过的数据。

为了解决安全和效率问题,SSL 使用了对称加密(加密和解密使用同样的密钥)和非对称加密(公钥加密,私钥解密)组合的方式:使用非对称加密的方式传输对称加密中生成密钥的种子(Pre-master secret),然后使用对称加密的方式对通信数据进行加密,既保障了密钥的安全性,也提高了加密速度。

补充:Master secret与session key关系

由于服务端和客户端都有一份相同的 PreMaster secret 和随机数,这个随机数将作为后面产生 Master secret 的种子,结合 PreMaster secret,客户端和服务端将计算出同样的 Master secret。

Master secret 是由一系列的 hash值组成的,它将作为数据加解密相关的 secret 的 Key Material。

Master secret 最终解析出来的数据如下:

其中 write MAC key 就是 session secret 或者说是 session key。

Client write MAC key 是客户端发数据的 session secret, Server write MAC secret 是服务端发送数据的 session key。

MAC(Message Authentication Code),是一个数字签名,用来验证数据的完整性,可以检测到数据是否被串改。

SSL 握手以及 TCP 握手关系

HTTPS 比 HTTP 要慢 2 到 100 倍

SSL 的慢分两种。一种是指通信慢。另一种是指由于大量消耗CPU 及内存等资源,导致处理速度变慢。

和使用 HTTP 相比,网络负载可能会变慢 2 到 100 倍。除去和TCP 连接、发送 HTTP 请求、响应以外,还必须进行 SSL 通信,

因此整体上处理通信量不可避免会增加。另一点是 SSL 必须进行加密处理。在服务器和客户端都需要进行加密和解密的运算处理。因此从结果上讲,比起 HTTP 会更多地消耗服务器和客户端的硬件资源,导致负载增强。

针对速度变慢这一问题,并没有根本性的解决方案,一般会使用SSL 加速器这种(专用服务器)硬件来改善该问题。该硬件为SSL 通信专用硬件,相对软件来讲,能够提高数倍 SSL 的计算速度。仅在 SSL 处理时发挥 SSL 加速器的功效,以分担负载。

Reference